
#ifndef __H_MUSCL_DATUM
#define __H_MUSCL_DATUM

#include <list>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
 
#define DATUM_TYPE_RAW               0
#define DATUM_TYPE_EMPTY             1
#define DATUM_TYPE_SIGNED_SHORT      2
#define DATUM_TYPE_UNSIGNED_SHORT    3
#define DATUM_TYPE_SIGNED_INT        4
#define DATUM_TYPE_UNSIGNED_INT      5
#define DATUM_TYPE_SIGNED_LONG       6
#define DATUM_TYPE_UNSIGNED_LONG     7
#define DATUM_TYPE_DOUBLE            8
#define DATUM_TYPE_CHAR              9
#define DATUM_TYPE_STRING           10
#define DATUM_TYPE_ARRAY            11

#define DATUM_SERIAL_RAW             'x'
#define DATUM_SERIAL_EMPTY           'n'
#define DATUM_SERIAL_SIGNED_SHORT    'q'
#define DATUM_SERIAL_UNSIGNED_SHORT  'w'
#define DATUM_SERIAL_SIGNED_INT      'e'
#define DATUM_SERIAL_UNSIGNED_INT    'r'
#define DATUM_SERIAL_SIGNED_LONG     't'
#define DATUM_SERIAL_UNSIGNED_LONG   'y'
#define DATUM_SERIAL_DOUBLE          'd'
#define DATUM_SERIAL_CHAR            'c'
#define DATUM_SERIAL_STRING          's'
#define DATUM_SERIAL_ARRAY           'a'



//////////////////////////////////////////////////////////////////////////  DATUM EXCEPTION  //////////////////////////////////////////////////////////////////////////
class DatumException {
  private:
    std::string     _message;

    void  setMessage( const std::string& message ) { _message = message; return; }

  public:
    DatumException( void );
    DatumException( const std::string& file, const unsigned long& line, const std::string& extra = "" );
    DatumException( const DatumException& ref );
    ~DatumException( void );

    std::string    getMessage( void ) const { return _message; }
};



//////////////////////////////////////////////////////////////////////////  DATUM CLASS  //////////////////////////////////////////////////////////////////////////
class Datum {
  private:
    // Data...
    short                       _type;
    void*                       _data;

    // Private methods...
    void                        copy( const Datum& ref );
    void                        realloc( const size_t& size );
    void                        make_array( void );
    std::list<Datum>::iterator  get_pos( const unsigned int& index );

    void                        set( const signed int& value );
    void                        set( const char& value );
    void                        set( const char* value );

  public:
    // Constructors...
    Datum( void );
    Datum( const Datum& ref );
    Datum( const signed int& value );
    Datum( const char& value );
    Datum( const char* value );
    ~Datum( void );

    // General operators...
    Datum&                      operator = ( const Datum& ref );

    // Assignment operators...
    Datum&                      operator = ( const signed int& value );
    Datum&                      operator = ( const char& value );
    Datum&                      operator = ( const char* value );

    // Conversion operators...
    operator                    signed int   ( void ) const                     { return *((signed int*)data()); }
    operator                    char         ( void ) const                     { return *((char*)data()); }
    operator                    const char*  ( void ) const                     { return (const char*)data(); }

    // Public accessor methods...
    void                        type( const short& type )                       { _type = type; }
    short                       type( void ) const                              { return _type; }
    void                        data( void* data )                              { _data = data; }
    void*                       data( void ) const                              { return _data; }

    // Array methods...
    Datum&                      append( const Datum& ref );
    Datum&                      at( const unsigned long& index );
    Datum&                      insert( const Datum& ref, const unsigned long& index );
    Datum&                      remove( const unsigned long& index );
    Datum&                      first( void );
    Datum&                      last( void );
    Datum&                      reverse( void );

    // General methods...
    void                        clear( void );
    std::string                 serialize( void ) const;
    void                        print( unsigned depth = 0 ) const;

    // Statics...
    static Datum                unserialize( const char* compact, unsigned int start = 0 );

};



#endif // End of inclusion guard

